/*
 * G53_ADC_example.c
 *
 * Created: 6/18/2014 1:19:50 PM
 *  Author: jerome.semette
 */ 

#include "sam.h"

volatile uint16_t uAdc_result;
volatile uint16_t uInter_Adc_Result;

 void Configure_TC0 (void) {
	
	    /*Enable TC0 Clock */
	    PMC->PMC_PCER0 = (0x1 << 23) ;  // TC0 Peripheral ID = 23
		/* Configure the TC0 to count at 750kHz (24 MHz / 32) and generate TIOA signal on RA and RC compare event  */
		TC0->TC_CHANNEL[0].TC_CMR = (TC_CMR_TCCLKS_TIMER_CLOCK3  | TC_CMR_ACPC_SET | TC_CMR_WAVE | TC_CMR_ACPA_CLEAR | TC_CMR_WAVSEL_UP_RC  );
		
		/*configure TIO output at 750kHz/60 = 50kHz  */
		TC0->TC_CHANNEL[0].TC_RA = (uint32_t)7;
		TC0->TC_CHANNEL[0].TC_RC = (uint32_t)15;
		
		/* Enable Compare register C interrupt */ 
		TC0->TC_CHANNEL[0].TC_IER |= TC_IER_CPCS | TC_IER_CPAS  ;
    
		/* Enable general ADC interrupt (ID 29)*/ 
		NVIC_EnableIRQ( TC0_IRQn ) ;
}

void TC0_Handler(void){
	uint32_t isr ;
	isr = TC0->TC_CHANNEL[0].TC_SR ;
	
	if (isr & TC_SR_CPCS )
	{
		/* Set test PIO (monitor start of conversion) */	
		PIOA->PIO_SODR = PIO_SODR_P0;
	}
}

static void Configure_ADC(void)
{

	/*Enable ADC Clock */
	PMC->PMC_PCER0 = (0x1 << 29);
	    
	/* Set ADC Hardware trigger to TC0 TIOA output*/
    ADC->ADC_MR |= ADC_MR_TRGSEL_ADC_TRIG1; 
    
	/* use div 1 to get and ADC clock equal to MCK/1 => 9.98MHz*/
    ADC->ADC_MR |= ADC_MR_DIV1_FORCE_DIV1 ;
	
	/* Set ADC start-up to 0 periods of ADCCLK*/
	ADC->ADC_MR |= ADC_MR_STARTUP_SUT0 ;
	
	/* Set Track time to 1 ADCCLK(TRACKTIM + 1) x ADCCLK periods) */
	ADC->ADC_MR |= (0x0 << ADC_MR_TRACKTIM_Pos) ;
	
	/*enable 2-bit enhanced resolution on one trig*/
	ADC->ADC_EMR |= ADC_EMR_OSR_OSR16;
	ADC->ADC_EMR |= ADC_EMR_ASTE_SINGLE_TRIG_AVERAGE;
	
    /* Disable PDC for ADC */
    ADC->ADC_PTCR = ADC_PTCR_RXTDIS;
    
	/* Perform dummy read in Last converted Data register to clear pending int. flag */
	ADC->ADC_LCDR;
	
	/* Enable ADC channel 2 and General Overrun interrupt */ 
    ADC->ADC_IER |= (ADC_IER_EOC2 | ADC_IER_GOVRE| ADC_IER_DRDY ) ;
	/* Enable general ADC interrupt (ID 29)*/ 
    NVIC_EnableIRQ( ADC_IRQn ) ;
	
	/* Enable internal hardware Trig*/ 
    ADC->ADC_MR |= ADC_MR_TRGEN;
	
	/* Enable ADC channel 2 input (AD2 <=> PA19 <=> Pin 3 on EXT connector of the I/O Xplained Pro) */
    ADC->ADC_CHER = (uint16_t) (0x1 << 2);

}

/*
 * Handles interrupts coming from the ADC.
 */
void ADC_Handler( void )
{
    uint32_t isr ;
	
	/* Read Interrupt status register*/
    isr = ADC->ADC_ISR;

    /* Check if RXBUFF interrupt appears */
    if (isr & ADC_ISR_EOC2)
    {
	  //Read Result from channel 2
      uInter_Adc_Result = ADC->ADC_CDR[2];
	}
	
	/* Check if General Overrun interrupt appears */
    if (isr & ADC_ISR_GOVRE)
    {
		/** Debug ** Put a breakpoint there to monitor General overrun */ 
		 while(1);
    }
	 
	if (isr & ADC_ISR_DRDY)
    {
		/* Get converted value after oversampling + decimation */
		uAdc_result = ADC->ADC_LCDR;
		/* Clear test PIO (monitor end of conversion) */	
		PIOA->PIO_CODR = PIO_CODR_P0; 
    } 
	  
}

void Configure_GPIOs()
{
	
	
	/*Enable PIOA Clock */
	PMC->PMC_PCER0 = (0x1 << 11); 
	
   /* Initialize pin for sample per second monitoring */
   PIOA->PIO_OER = PIO_OER_P0;
   PIOA->PIO_PUDR = PIO_PUDR_P0;
   
   /* Use PA17 for PCK1 output (Peripheral B) */ 
   PIOA->PIO_ABCDSR[0] = PIO_ABCDSR_P6; 
   PIOA->PIO_PUDR = PIO_PUDR_P6;
   PIOA->PIO_PPDDR = PIO_PPDDR_P6;

   /* Disable pull-up on ADC channel 2 line */
   PIOA->PIO_SODR = PIO_SODR_P19;


}



void Init_System(void) {
		
	/* Disable Watchdog*/
	WDT->WDT_MR = 0x00;

	/* Set FWS according to default clock configuration */
	EFC->EEFC_FMR = EEFC_FMR_FWS(1);
	
	/* Switch to 24MHz */
	PMC->CKGR_MOR |= (CKGR_MOR_KEY_PASSWD| CKGR_MOR_MOSCRCF_24_MHz);


	};



void main( void )
{

   // Initialize System (PLL config + Watchdog disable)
   Init_System();

   // configure GPIOs
   Configure_GPIOs();
   
   // configure ADC 
   Configure_ADC(); 
   
   // configure Timer counter 0   
   Configure_TC0();
   
   // Start Timer counter 0
   TC0->TC_CHANNEL[0].TC_CCR = (TC_CCR_CLKEN | TC_CCR_SWTRG); 
 
    while(1);
}
